﻿using System;
using System.Collections.Generic;

namespace FROG
{
    public enum ListAction
    {
        ItemAdded,
        ItemRemoved,
        ItemChanged,
        ListCleared
    }

    public class ListChangedEventArgs<T> : EventArgs
    {
        public ListChangedEventArgs(T item, int index, ListAction action)
        {
            _item = item;
            _index = index;
            _action = action;
        }

        private T _item;
        public T Item
        {
            get { return _item; }
            set { _item = value; }
        }

        private int _index;
        public int Index
        {
            get { return _index; }
            set { _index = value; }
        }


        private ListAction _action;
        public ListAction Action
        {
            get { return _action; }
            set { _action = value; }
        }
    }

    public delegate void ListChangedEventHandler<T>(object sender, ListChangedEventArgs<T> e);

    public class ObservableList<T> : IList<T>
    {
        private List<T> _list = new List<T>();

        public event ListChangedEventHandler<T> ItemAdded;
        public event ListChangedEventHandler<T> ItemRemoved;
        public event ListChangedEventHandler<T> ItemChanged;
        public event ListChangedEventHandler<T> ListCleared;

        protected void OnItemAdded(T item, int index)
        {
            if (ItemAdded != null)
                ItemAdded(this, new ListChangedEventArgs<T>(item, index, ListAction.ItemAdded));
        }

        protected void OnItemRemoved(T item, int index)
        {
            if (ItemRemoved != null)
                ItemRemoved(this, new ListChangedEventArgs<T>(item, index, ListAction.ItemRemoved));
        }

        protected void OnItemChanged(T item, int index)
        {
            if (ItemChanged != null)
                ItemChanged(this, new ListChangedEventArgs<T>(item, index, ListAction.ItemChanged));
        }

        protected void OnListCleared()
        {
            if (ListCleared != null)
                ListCleared(this, new ListChangedEventArgs<T>(default(T), -1, ListAction.ListCleared));
        }

        #region IList<T> Members

        public int IndexOf(T item)
        {
            return _list.IndexOf(item);
        }

        public void Insert(int index, T item)
        {
            _list.Insert(index, item);
            OnItemAdded(item, index);
        }

        public void RemoveAt(int index)
        {
            T item = default(T);
            lock (_list)
            {
                item = _list[index];
                _list.RemoveAt(index);
            }
            OnItemRemoved(item, index);
        }

        public T this[int index]
        {
            get
            {
                return _list[index];
            }
            set
            {
                _list[index] = value;
                OnItemChanged(value, index);
            }
        }

        #endregion

        #region ICollection<T> Members

        public void Add(T item)
        {
            int index = -1;
            lock (_list)
            {
                _list.Add(item);
                index = _list.Count - 1;
            }
            OnItemAdded(item, index);
        }

        public void Clear()
        {
            _list.Clear();
            OnListCleared();
        }

        public bool Contains(T item)
        {
            return _list.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            _list.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return _list.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(T item)
        {
            int index = -1;
            lock (_list)
            {
                index = _list.IndexOf(item);
                if (index < 0)
                    return false;
                else
                    _list.RemoveAt(index);
            }
            OnItemRemoved(item, index);
            return true;
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return (_list as System.Collections.IEnumerable).GetEnumerator();
        }

        #endregion
    }
}
